package org.ace.logic.raid;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import static org.ace.logic.raid.protocol.RaidProtocol.*;
import javax.annotation.Resource;
import javax.sound.midi.Receiver;

import io.netty.channel.Channel;

import org.ace.Manager.interfaces.IHandlerManager;
import org.ace.basicdata.IBasicDataCentral;
import org.ace.basicdata.model.RaidBasicData;
import org.ace.biz.user.IPlayerBiz;
import org.ace.biz.user.ITeamBiz;
import org.ace.endingCode.SocketModel;
import org.ace.event.model.RaidOverEvent;
import org.ace.logic.IoHandler;
import org.ace.logic.raid.dto.EnterDTO;
import org.ace.logic.raid.dto.PlayerRaidModel;
import org.ace.logic.raid.impl.RaidHandlerServImpl;
import org.ace.protocol.Protocol;
import org.springframework.context.ApplicationListener;

public abstract class RaidHandler implements ApplicationListener<RaidOverEvent>, IoHandler {

	@Override
	public void onApplicationEvent(RaidOverEvent event)
	{
		int raid = event.getRaidArea();
		playerRaidMap.remove(raid);
		manager.unregister(raid);
	}
	
	private IHandlerManager manager;
	
	//获取副本 基础数据模型
	@Resource(name="raidBasicDataCenteral")
	private IBasicDataCentral<RaidBasicData> raidBasicDataCenteral;
	
	@Resource(name="teamBiz")
	private ITeamBiz teamBiz;
	
	@Resource(name="playerBiz")
	private IPlayerBiz playerBiz;
	 /**副本ID 生成器*/
	private AtomicInteger key=new AtomicInteger(0);
	
	/*玩家所在 副本映射 副本可以一个人进入也可以多人进入*/
	private Map<Integer,PlayerRaidModel> playerRaidMap=new ConcurrentHashMap<Integer, PlayerRaidModel>();
	
	@Override
	public void messageReceived(Channel channel, SocketModel message) {
		switch(message.getCommand())
		{
		case ENTER_CREQ:
			//在当前模块处理 并进行副本创建
			enter(channel,message);
			break;
		default:
			received(channel,message);
			break;
		}

	}

	private void received(Channel channel, SocketModel message) {
		Integer userId=playerBiz.getPlayerId(channel);
		//字典存在才继续,已经登录
		if(userId == null) return;
		
		//玩家和副本的映射里有 角色id 
		if(playerRaidMap.containsKey(userId))
		{
			// 所有副本中存在 这个副本
			if(manager.hasServ(playerRaidMap.get(userId).getArea()))
			{ 
				//接受 其他副本消息分发 
				 manager.get(playerRaidMap.get(userId).getArea()).messageReceived(channel, message);
				
				 //越权判断
				 if(message.getCommand()==LEAVE_CREQ)
				 {
					 // 离开 移除映射
					 leave(userId);
				 }
			}
		}
		
	}

	private void leave(Integer userId) {
		playerRaidMap.remove(userId);		
	}

	private void enter(Channel channel, SocketModel<Integer> message) {
		Integer raidCode = message.getMessage();
		//看副本是否存在，没有数据异常 直接无视
		if(!raidBasicDataCenteral.has(raidCode)) return;
		//获取副本基础数据
		RaidBasicData data=raidBasicDataCenteral.get(raidCode);
		
		Integer userId=playerBiz.getPlayerId(channel);
		//副本要求人数
		if(data.getNum()==-1)
		{
			//只能单人进入，没有队伍不让进
			if(teamBiz.hasTeam(userId))
			{
				//返回空 ，说明进入条件不满足
				write(channel,Protocol.TYPE_RAID,-1,ENTER_SRES,null);
			}
			else
			{
				write(channel,Protocol.TYPE_RAID,-1,ENTER_SRES,
						new EnterDTO(createRaid(userId,key.getAndIncrement(),raidCode)));
			}
		}
	}

	private void write(Channel channel, int type, int area, int command,Object message) {
		channel.writeAndFlush(createSocketModel(type,area,command,message));		
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	private Object createSocketModel(int type, int area, int command,Object message) {
	    SocketModel sm=new SocketModel();
	    sm.setType(type);
	    sm.setArea(area);
	    sm.setCommand(command);
	    sm.setMessage(message);
	    return sm;
	}

	/**创建副本模块,发送给客户端,创建副本对象*/
	private PlayerRaidModel createRaid(Integer userId, int area,Integer raidCode) {
			//创建副本模块 发送给客户端
		    PlayerRaidModel model = new PlayerRaidModel();
			model.setArea(area);
			model.setUserId(userId);
			model.setRaidCode(raidCode);
			//创建 副本对象
			
			RaidHandlerServImpl raidHanlerImpl =createRaidHandlerServImpl();
			raidHanlerImpl.setArea(model.getArea());
			raidHanlerImpl.setType(Protocol.TYPE_RAID);
			raidHanlerImpl.init(raidCode);
			manager.register(area,raidHanlerImpl);
			//将玩家 与自己所在的 副班映射保存关联起来
			playerRaidMap.put(userId, model);
			return model;
			
	}

	public abstract RaidHandlerServImpl createRaidHandlerServImpl();
	@Override
	public void channelClose(Channel channel) {
		//断开连接，移除映射
		Integer userId=playerBiz.getPlayerId(channel);
		if(userId==null) return;
		if(!playerRaidMap.containsKey(userId))
		{
			return;
		}
		if(manager.hasServ(playerRaidMap.get(userId).getArea()))
		{
			//有区域码 在执行下一步，保证数据的安全性，将副本用列表存起来
			manager.get(playerRaidMap.get(userId).getArea()).Colse(channel);
			leave(userId);
		}
	}
	
	@Resource(name="raidManager")
    protected void setManager(IHandlerManager manager)
    {
    	this.manager=manager;
    }
    
	@Override
	public void onShake(Channel channel) {
		// TODO Auto-generated method stub

	}

}
